package com.im.tcp.utils;

import com.alibaba.fastjson.JSONObject;
import com.lld.im.common.constants.Constants;
import com.lld.im.common.enums.ConnectStatusEnum;
import com.lld.im.common.model.UserSession;
import io.netty.channel.Channel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 管理用户的channel连接
 */
public class SessionSocketHolder {
    /**
     * 保存用户的连接
     */
    private static final Map<UserSession, NioSocketChannel> CHANNEL_MAP=new ConcurrentHashMap<>();


    public static void put(UserSession key, NioSocketChannel v){
        CHANNEL_MAP.put(key, v);
    }

    public static NioSocketChannel get(UserSession key){
        return CHANNEL_MAP.get(key);
    }

    public static NioSocketChannel get(String appId,String userId,String clientType,String imei){
        NioSocketChannel nioSocketChannel = null;
        for (NioSocketChannel channel : CHANNEL_MAP.values()) {
            String userIdC = (String) channel.attr(AttributeKey.valueOf(Constants.USERID)).get();
            String appIdC = (String) channel.attr(AttributeKey.valueOf(Constants.APPID)).get();
            Integer clientTypeC = (Integer) channel.attr(AttributeKey.valueOf(Constants.CLIENT_TYPE)).get();
            String imeiC = (String) channel.attr(AttributeKey.valueOf(Constants.IMEI)).get();
            if(Objects.equals(userIdC, userId)
                    &&Objects.equals(appId, appIdC)
                    &&Objects.equals(clientTypeC.toString(), clientType)&&
            Objects.equals(imeiC, imei)){
                nioSocketChannel=channel;
                break;
            }
        }
        return nioSocketChannel;
    }

    public static void remove(UserSession key){
         CHANNEL_MAP.remove(key);
    }

    public static Map<UserSession, NioSocketChannel> getChannelMap() {
        return CHANNEL_MAP;
    }

    /**
     * 修改用户状态 只断开连接 不会删除redis缓存
     * @param channel
     */
    public static void offlineUserSession(Channel channel) {
        UserSession userSession = createUserSession(channel);
        //TODO 断开连接 移除系统缓存
        SessionSocketHolder.remove(userSession);
        RedissonClient redissonClient = SpringContextHolder.getBean(RedissonClient.class);
        RMap<String, String> map = redissonClient.getMap(userSession.getAppId() +
                Constants.RedissonConfig.USER_SESSION_KEY + userSession.getUserId());
        String userSessionStr = map.get(userSession.getClientType()+":"+userSession.getImei());
        //对于redis中数据 不删除 只是修改连接状态
        if(userSessionStr!=null){
            UserSession userSessionRedis
                    = JSONObject.parseObject(userSessionStr, UserSession.class);
            userSessionRedis.setConnectState(ConnectStatusEnum.CLOSE.getCode());
            map.put(userSession.getClientType().toString(),JSONObject.toJSONString(userSessionRedis));
        }
        //关闭连接
        channel.close();
    }

    /**
     * 删除用户在系统所有缓存信息
     * @param channel
     */
    public static void removeUserSession(Channel channel){
        UserSession userSession =createUserSession(channel);
        //TODO 断开连接 移除系统缓存
        SessionSocketHolder.remove(userSession);
        RedissonClient redissonClient = SpringContextHolder.getBean(RedissonClient.class);
        RMap<String, String> map = redissonClient.getMap(userSession.getAppId() +
                Constants.RedissonConfig.USER_SESSION_KEY + userSession.getUserId());
        map.remove(userSession.getClientType()+":"+userSession.getImei());
        channel.close();
    }

    private static UserSession createUserSession(Channel channel){
        String userId = (String) channel.attr(AttributeKey.valueOf(Constants.USERID)).get();
        String appId = (String) channel.attr(AttributeKey.valueOf(Constants.APPID)).get();
        Integer clientType = (Integer) channel.attr(AttributeKey.valueOf(Constants.CLIENT_TYPE)).get();
        String imei = (String) channel.attr(AttributeKey.valueOf(Constants.IMEI)).get();
        return  new UserSession(appId,userId,clientType,imei);
    }

    public static List<Channel> getUserSessionChannelByUserId(String appId,String userId){
        List<Channel> channels=new ArrayList<>();
        for (UserSession userSession : CHANNEL_MAP.keySet()) {
            if(userSession.getUserId().equals(userId)&&
                    userSession.getAppId().equals(appId)){
                channels.add(get(userSession));
            }
        }
        return channels;
    }
}
